package http

import (
	"context"
	"crypto/tls"
	"fmt"
	"net/http"
	"time"

	"gitee.com/mkwchecking/sr-core/net/http/middleware"
	"github.com/gin-gonic/gin"
	"github.com/google/wire"
)

var Provider = wire.NewSet(
	NewDefault,
	NewHttpServer,
)

func NewDefault(opts ...Options) (*http.Server, error) {
	return NewHttpServer(nil, opts...)
}

func NewHttpServer(cfg *HttpConfig, opts ...Options) (*http.Server, error) {
	if cfg == nil {
		cfg = defaultConfig()
	}
	for _, opt := range opts {
		opt(cfg)
	}

	if cfg.Handler == nil {
		gin.SetMode(cfg.Mode)
		GetInstanceEngine().Use(cfg.Middlewares...)
		cfg.Handler = GetInstanceEngine()
	}

	/*
		if cfg.Session != nil && cfg.Session.Enable {
			// 加载session中间件
			sessMid, err := session.Middleware(context.Background(), cfg.Session)
			if err != nil {
				return nil, err
			}

			GetInstanceEngine().Use(sessMid)
		}
	*/

	if len(cfg.WhiteList) > 0 {
		GetInstanceEngine().Use(middleware.IncomeWhiteList(cfg.WhiteList...))
	}

	if cfg.Health != nil && cfg.Health.Enable {
		InitHealthCheck(GetInstanceEngine(), cfg.Health)
	}

	var tls *tls.Config
	var err error
	if cfg.SSL != nil && cfg.SSL.Enable {
		tls, err = NewTLS(cfg.SSL)
		if err != nil {
			return nil, err
		}
	}

	srv := &http.Server{
		Addr:         fmt.Sprintf("%s:%d", cfg.Host, cfg.Port),
		Handler:      cfg.Handler,
		ReadTimeout:  cfg.Timeout * time.Millisecond,
		WriteTimeout: cfg.Timeout * time.Millisecond,
		TLSConfig:    tls,
	}

	return srv, nil
}

func NewServer(cfg *HttpConfig, opts ...Options) (IHttpServer, error) {
	srv, err := NewHttpServer(cfg, opts...)
	if err != nil {
		return nil, err
	}
	return &transportSvr{
		srv:   srv,
		https: srv.TLSConfig != nil,
	}, nil
}

type transportSvr struct {
	srv   *http.Server
	https bool
}

func (s *transportSvr) Router(paths string, hdls ...gin.HandlerFunc) *gin.RouterGroup {
	return s.getEngine().Group(paths, hdls...)
}

// Use implements IHttpServer.
func (s *transportSvr) Use(middleware ...gin.HandlerFunc) IHttpServer {
	if s.srv == nil || s.srv.Handler == nil {
		return s
	}

	if engine, ok := s.srv.Handler.(*gin.Engine); ok {
		engine.Use(middleware...)
	} else {
		GetInstanceEngine().Use(middleware...)
	}

	return s
}

func (s *transportSvr) getEngine() *gin.Engine {
	return s.srv.Handler.(*gin.Engine)
}

func (s *transportSvr) Start(ctx context.Context) error {
	if s.https {
		return s.srv.ListenAndServeTLS("", "")
	}
	return s.srv.ListenAndServe()
}

func (s *transportSvr) Stop(ctx context.Context) error {
	return s.srv.Shutdown(ctx)
}
